package main

import (
	"fmt"
	"reflect"
)

type userR1 struct {
	id   int    `json:"id"`
	Name string `json:"userName"`
}

func (u userR1) Hello(str string) {
	fmt.Println("user say ", str)
}

func reflect_type(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println("TypeOf()", t)
	k := t.Kind()
	fmt.Println("Kind()", k)
	v := reflect.ValueOf(a)
	switch k {
	case reflect.Float64:
		fmt.Println("a is float64:", v.Float())
	case reflect.String:
		fmt.Println("a is string:", v.String())
	case reflect.Struct:
		fmt.Printf("a is struct. \n	Field(0):%#v \n	Method(0):%#v \n", t.Field(0), t.Method(0))
	case reflect.Pointer:
		fmt.Println("a is pointer:", v.Pointer())
	default:
		fmt.Println("a unknown")
	}
}

// 反射修改值
func reflect_set_value(a interface{}) {
	v := reflect.ValueOf(a)
	k := v.Kind()
	switch k {
	case reflect.Float64:
		v.SetFloat(6.9)
	case reflect.Pointer:
		v.Elem().SetFloat(7.9)
	}
}

// 修改结构体的值
func reflect_set_value_for_user(u interface{}) {
	v := reflect.ValueOf(u)
	v = v.Elem()
	v.FieldByName("Name").SetString("zxy")

	// panic: reflect: reflect.Value.SetInt using value obtained using unexported field
	//v.FieldByName("id").SetInt(10)
}

func getTagForUser(u interface{}) {
	t := reflect.TypeOf(u)
	if t.Kind() == reflect.Pointer {
		t = t.Elem()
	}
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		fmt.Printf("field:%v tag:%v \n", f.Name, f.Tag.Get("json"))
	}
}

func invokeMethodForUser(u interface{}) {
	v := reflect.ValueOf(u)
	if v.Kind() == reflect.Pointer {
		v = v.Elem()
	}
	m := v.MethodByName("Hello")
	args := []reflect.Value{reflect.ValueOf(" 你好")}
	m.Call(args)
}

func main() {
	var a float64 = 3.4
	reflect_type(a)

	var b = "Hello"
	reflect_type(b)

	var u = userR1{id: 123, Name: "Jasper"}
	reflect_type(u)

	var ptr = &a
	reflect_type(ptr)

	reflect_set_value(&a)
	//reflect_set_value(a)
	fmt.Println("main a:", a)

	reflect_set_value_for_user(&u)
	fmt.Println("main u:", u)

	getTagForUser(u)
	getTagForUser(&u)

	invokeMethodForUser(u)
	invokeMethodForUser(&u)
}
